package cn.mhome.merchant.dao.spring.data.repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * criteria 写法示例：
 * 查询时支持下列比较符
 * 	EQ(" = "), NE(" <> "), LIKE(" like "), GT(" > "), LT(" < "), GTE(" >= "), LTE(" <= ");
 * 
 * 一个条件
 * (b > 1)
 * new Criteria("b", Operator.GT, 1)
 * 
 * 两个条件 
 * (a > 1) and (b > 2)
 * new Criteria(Connector.AND, new Criteria("a", Operator.GT, 1), 
 * 		new Criteria("b", Operator.GT, 1))
 * 
 * 嵌套条件
 * (a > 1) and ((b > 2) or (c > 3))
 *  * new Criteria(Connector.AND, new Criteria("b", Operator.GT, 2), 
 * 		new Criteria(Connector.OR, new Criteria("c", Operator.GT, 3), 
 *      	new Criteria("a", Operator.GT, 1));
**/

public class Criteria {
	private List<Criteria> subCriteria = new ArrayList<Criteria>();
	private List<Criteria> standaloneCriteria = new ArrayList<Criteria>();
	private Connector subConnector;

	private String simpleFieldName = null;
	private String simpleFieldAlias = null;
	private Operator simpleOperator = null;
	private Object simpleValue = null;
	private String perfix = null;
	private String postfix = null;
	
	public Criteria(Connector connector) {
		this.subConnector = connector;
	}

	public Criteria(String fieldName, Operator operator, Object value) {
		this.simpleFieldName = fieldName.trim();
		this.simpleFieldAlias = fieldName.trim();
		this.simpleOperator = operator;
		this.simpleValue = value;
	}

	public Criteria(String fieldName, String fieldAlias, Operator operator, Object value) {
		this.simpleFieldName = fieldName.trim();
		this.simpleFieldAlias = fieldAlias.trim();
		this.simpleOperator = operator;
		this.simpleValue = value;
	}

	public Criteria(Connector connector, Criteria... subCrietria) {
		this.subConnector = connector;
		for (Criteria criteria : subCrietria) {
			this.subCriteria.add(criteria);
		}
	}

	public Criteria addSubCriteria(Connector connector) {
		Criteria ct = new Criteria(connector);
		subCriteria.add(ct);
		return ct;
	}

	public Criteria addSimpleSubCriteria(String fieldName, Operator operator, Object value) {
		Criteria ct = new Criteria(fieldName, operator, value);
		subCriteria.add(ct);
		return ct;
	}

	public Criteria addSimpleSubCriteria(String fieldName, String fieldAlias, Operator operator, Object value) {
		Criteria ct = new Criteria(fieldName, fieldAlias, operator, value);
		subCriteria.add(ct);
		return ct;
	}

	public Criteria addStandaloneCriteria(String fieldName, Object value) {
		// 独立条件，连接符不需要使用，随便指定一个EQ
		Criteria ct = new Criteria(fieldName, Operator.EQ, value);
		standaloneCriteria.add(ct);
		return ct;
	}

	public Criteria addStandaloneCriteria(String fieldName, String fieldAlias, Object value) {
		// 独立条件，连接符不需要使用，随便指定一个EQ
		Criteria ct = new Criteria(fieldName, fieldAlias, Operator.EQ, value);
		standaloneCriteria.add(ct);
		return ct;
	}

	public void addSimpleExpression(String fieldName, Operator operator, Object value) {
		this.simpleFieldName = fieldName.trim();
		this.simpleFieldAlias = fieldName.trim();
		this.simpleOperator = operator;
		this.simpleValue = value;
	}

	public void addSimpleExpression(String fieldName, String fieldAlias, Operator operator, Object value) {
		this.simpleFieldName = fieldName.trim();
		this.simpleFieldAlias = fieldAlias.trim();
		this.simpleOperator = operator;
		this.simpleValue = value;
	}

	public String getQueryExpression() {
		StringBuffer sb = new StringBuffer();
        if ((hasSimpleExpression() == true)||(hasSubCriteria() == true)) {
		    sb.append(this.getPerfix()).append(" ");
        }
		boolean addConnector = false;
		if (hasSimpleExpression() == true) {
			if (hasSubCriteria() == true) {
				sb.append("(");
			}
			sb.append(this.simpleFieldName);
			sb.append(this.simpleOperator.getVal());
			sb.append(":");
			sb.append(this.simpleFieldAlias.replaceAll("\\.", "_"));
			if (hasSubCriteria() == true) {
				sb.append(")");
			}
			addConnector = true;
		}
		for (Criteria c : subCriteria) {
			if (addConnector == true) {
				sb.append(this.subConnector.getVal());
			} else {
				addConnector = true;
			}
			sb.append("(");
			sb.append(c.getQueryExpression());
			sb.append(")");
		}
        if ((hasSimpleExpression() == true)||(hasSubCriteria() == true)) {
    		sb.append(" ").append(this.getPostfix());
        }
		return sb.toString();
	}

	private boolean hasSubCriteria() {
		return subCriteria.size() > 0;
	}

	private boolean hasSimpleExpression() {
		return this.simpleFieldName != null;
	}

	public Map<String, Object> getParameterAndValue() {
		Map<String, Object> pv = new HashMap<String, Object>();
		if (hasSimpleExpression() == true) {
			pv.put(this.simpleFieldAlias.replaceAll("\\.", "_"), this.simpleValue);
		}
		for (Criteria c : subCriteria) {
			pv.putAll(c.getParameterAndValue());
		}
		for (Criteria c : standaloneCriteria) {
			pv.put(c.simpleFieldAlias.replaceAll("\\.", "_"), c.simpleValue);
		}
		return pv;
	}

	public String getPerfix() {
		return (perfix == null) ? "" : perfix;
	}

	public void setPerfix(String perfix) {
		this.perfix = perfix;
	}

	public String getPostfix() {
		return (postfix == null) ? "" : postfix;
	}

	public void setPostfix(String postfix) {
		this.postfix = postfix;
	}
}
